package com.stock.core.service.stock;

import com.stock.api.domain.stock.BusinessHistoryBean;
import com.stock.api.domain.stock.StockCodeBean;
import com.stock.api.domain.stock.StockConfigureBean;
import com.stock.api.domain.stock.StockHistoryBean;
import com.stock.api.service.stock.BusinessHistoryService;
import com.stock.api.service.stock.StockCodeService;
import com.stock.api.util.StockUtils;
import com.stock.comm.util.DateUtil;
import com.stock.comm.util.PropertyUtils;
import com.stock.core.persistence.reader.stock.BusinessHistoryReaderMapper;
import com.stock.core.persistence.reader.stock.StockConfigureReaderMapper;
import com.stock.core.persistence.writer.stock.BusinessHistoryWriterMapper;
import com.stock.core.persistence.writer.stock.StockConfigureWriterMapper;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * <p>类说明</p>
 *
 * @author 张峰 zfvip_it@163.com
 * @createTime: 2016/9/14 10:00
 */
@Service("businessHistoryService")
public class BusinessHistoryServiceImpl implements BusinessHistoryService {

    private static final Logger LOGGER = LoggerFactory.getLogger(BusinessHistoryServiceImpl.class);

    @Resource
    private StockConfigureReaderMapper stockConfigureReaderMapper;

    @Resource
    private StockConfigureWriterMapper stockConfigureWriterMapper;

    @Resource
    private BusinessHistoryReaderMapper businessHistoryReaderMapper;

    @Resource
    private BusinessHistoryWriterMapper businessHistoryWriterMapper;

    @Resource
    private StockCodeService stockCodeService;

    @Resource
    private RedisTemplate redisTemplate;

    /**
     * 创建线程池
     */
    ExecutorService pool = null;

    /**
     * 分析股票数据
     */
    public void startStockBusinessData() throws Exception {
        //获取股票配置信息
        final List<StockConfigureBean> list = stockConfigureReaderMapper.queryAll();
        if (list != null && list.size() > 0) {
            int size = list.size();
            pool = Executors.newFixedThreadPool(size > 10 ? 10 : size);

            List<Future> rowResult = new CopyOnWriteArrayList<>();
            for (int i = 0; i < size; i++) {
                final int finalI = i;
                rowResult.add(pool.submit(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            StockConfigureBean stockConfigureBean = list.get(finalI);
                            /**分析股票数据*/
                            analysiBusinessHistory(stockConfigureBean);
                        } catch (Exception e) {
                            LOGGER.error("分析股票：" + list.get(finalI).getStockCode() + "成交数据失败！", e);
                        }
                    }
                }));
            }
            //等待处理结果
            for (Future f : rowResult) {
                f.get();
            }
            //启动一次顺序关闭，执行以前提交的任务，但不接受新任务。如果已经关闭，则调用没有其他作用
            pool.shutdown();
        }
    }

    /**
     * 分析股票数据
     *
     * @param stockConfigureBean
     */
    public void analysiBusinessHistory(StockConfigureBean stockConfigureBean) throws Exception {
        List<StockCodeBean> codeBeanList = new ArrayList<>();
        StockCodeBean stockCodeBean = stockCodeService.selectByStockCode(stockConfigureBean.getStockCode());
        codeBeanList.add(stockCodeBean);
        //获取股票实时数据
        List<StockHistoryBean> historyBeanList = StockUtils.getStockHistoryData(codeBeanList);
        if (historyBeanList != null && !historyBeanList.isEmpty()) {

            //获取未买入或者未卖出的股票业务数据
            List<BusinessHistoryBean> businessHistoryBeanList = businessHistoryReaderMapper.selectBusinessHistory(historyBeanList.get(0));

            if (businessHistoryBeanList != null && !businessHistoryBeanList.isEmpty()) {
                //计算是否买入和卖出
                calcBusinessHistory(historyBeanList.get(0), businessHistoryBeanList, stockConfigureBean);
            }
        }
    }

    /***
     * 计算是否买入或卖出
     *
     * @param stockHistoryBean
     * @param businessHistoryBeanList
     * @param stockConfigureBean
     */
    private void calcBusinessHistory(StockHistoryBean stockHistoryBean, List<BusinessHistoryBean> businessHistoryBeanList, StockConfigureBean stockConfigureBean) throws Exception {
        LOGGER.debug("【" + stockConfigureBean.getStockCode() + " " + stockConfigureBean.getStockName() + "】涨跌幅低于：" + stockConfigureBean.getSmallBuyIn() + "买入，高于：" + stockConfigureBean.getWillSellOut() + "卖出 ");
        for (BusinessHistoryBean businessHistoryBean : businessHistoryBeanList) {
            //1、计算涨跌幅 当前价-（买入或者卖出价格）/ （买入或者卖出价格）
            BigDecimal changeRate = stockHistoryBean.getClosePrice().subtract(businessHistoryBean.getBusinessPrice()).divide(businessHistoryBean.getBusinessPrice(), 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100));
            //更新我的股票涨跌幅
            StockUtils.getChangeRateMap().put(businessHistoryBean.getStockCode(), changeRate);

            //成交方向  01:买入  02:卖出
            if ((StringUtils.equals(businessHistoryBean.getBusinessDirection(), "02") && changeRate.doubleValue() <= stockConfigureBean.getSmallBuyIn().doubleValue())
                    || StringUtils.equals(businessHistoryBean.getBusinessDirection(), "01")) {
                if (changeRate.doubleValue() >= stockConfigureBean.getWillSellOut().doubleValue() || (changeRate.doubleValue() <= stockConfigureBean.getSmallBuyIn().doubleValue() && StringUtils.isBlank(businessHistoryBean.getIsBuy()))) { //涨幅大于卖出 //涨幅小于买入 并且买入的未买入
                    LOGGER.debug("【" + stockConfigureBean.getStockCode() + " " + stockConfigureBean.getStockName() + "】涨跌幅：（" + stockHistoryBean.getClosePrice() + "-" + businessHistoryBean.getBusinessPrice() + ")/" + businessHistoryBean.getBusinessPrice() + " = " + changeRate);
                    if (StringUtils.equals(businessHistoryBean.getBusinessDirection(), "01")) {
                        //原买入处理
                        sellIn(changeRate, businessHistoryBean, stockHistoryBean, stockConfigureBean);
                    } else if (StringUtils.equals(businessHistoryBean.getBusinessDirection(), "02") && StringUtils.isBlank(businessHistoryBean.getIsBuy()) &&
                            changeRate.doubleValue() <= stockConfigureBean.getSmallBuyIn().doubleValue() && stockConfigureBean.getBusinessAmount().subtract(stockConfigureBean.getBuyAmount()).doubleValue() >= 0) {
                        //原卖出处理
                        sellOut(changeRate, businessHistoryBean, stockHistoryBean, stockConfigureBean);
                    } else if (stockHistoryBean.getChangeRate().doubleValue() <= stockConfigureBean.getSameDayIn().doubleValue()) {
                        //当天跌幅小于买入
                        sameDayIn(stockHistoryBean, stockConfigureBean);
                    } else {
                        //更新市值
                        updateBusinessAmount(stockConfigureBean);
                    }
                } else if (stockHistoryBean.getChangeRate().doubleValue() <= stockConfigureBean.getSameDayIn().doubleValue()) {
                    //当天跌幅小于买入
                    sameDayIn(stockHistoryBean, stockConfigureBean);
                } else {
                    //更新市值
                    updateBusinessAmount(stockConfigureBean);
                }
            } else if (stockHistoryBean.getChangeRate().doubleValue() <= stockConfigureBean.getSameDayIn().doubleValue()) {
                //当天跌幅小于买入
                sameDayIn(stockHistoryBean, stockConfigureBean);
            } else {
                //更新市值
                updateBusinessAmount(stockConfigureBean);
            }
        }
    }

    /**
     * @param stockHistoryBean
     * @param historyBean
     * @return
     */
    private BusinessHistoryBean getBusinessHistoryBean(StockHistoryBean stockHistoryBean, BusinessHistoryBean historyBean,
                                                       StockConfigureBean stockConfigureBean) {
        BusinessHistoryBean businessHistoryBean = new BusinessHistoryBean();
        businessHistoryBean.setBusinessDate(stockHistoryBean.getStockDate());//成交日期
        businessHistoryBean.setBusinessTime(DateUtil.formatCurrentDatetime());//成交时间
        businessHistoryBean.setStockCode(stockHistoryBean.getStockCode());//股票代码
        businessHistoryBean.setBusinessPrice(stockHistoryBean.getClosePrice());//成交价格
        businessHistoryBean.setPreSalePrice(stockHistoryBean.getClosePrice().multiply(stockConfigureBean.getWillSellOut().divide(new BigDecimal(100))).add(stockHistoryBean.getClosePrice()).setScale(4, BigDecimal.ROUND_HALF_UP));//预卖价格
        //计算成交数量
        int businessNumber = new BigDecimal(PropertyUtils.getIntValue("historical.analysis.amount", 10000)).divide(stockHistoryBean.getClosePrice(), 2).intValue();
        businessNumber = businessNumber / 100;
        businessNumber = businessNumber * 100;
        businessHistoryBean.setBusinessNumber(businessNumber);
        businessHistoryBean.setBusinessNumber(businessNumber);//成交数量
        businessHistoryBean.setBusinessAmount(stockHistoryBean.getClosePrice().multiply(new BigDecimal(businessNumber)));//成交金额
        //计算手续费 按照万三计算，最少5元
        BigDecimal sumFare = businessHistoryBean.getBusinessAmount().multiply(new BigDecimal(0.0003)).setScale(4, BigDecimal.ROUND_HALF_UP);
        businessHistoryBean.setSumFare(sumFare);
        if (sumFare.doubleValue() < 5)
            businessHistoryBean.setSumFare(new BigDecimal(5));

        if (historyBean != null)
            businessHistoryBean.setRsourceId(historyBean.getId());//来源ID
        //创建人
        businessHistoryBean.setCreateUser("0000");
        businessHistoryBean.setCreateDate(DateUtil.formatCurrentDate());
        businessHistoryBean.setCreateTime(new Date());
        return businessHistoryBean;
    }

    /**
     * 当天跌幅小于买入
     *
     * @param stockHistoryBean
     * @param stockConfigureBean
     */
    private void sameDayIn(StockHistoryBean stockHistoryBean, StockConfigureBean stockConfigureBean) {
        BusinessHistoryBean businessHistoryBean = getBusinessHistoryBean(stockHistoryBean, null, stockConfigureBean);
        //成交方向  01:买入  02:卖出
        businessHistoryBean.setBusinessDirection("01");//买入
        //新增
        businessHistoryWriterMapper.insertSelective(businessHistoryBean);
        //更新配置信息
        updatetockonfigure(businessHistoryBean, null);
        //更新缓存
        updateRedis(businessHistoryBean);
    }

    /**
     * 原买入处理
     *
     * @param changeRate
     * @param businessHistoryBeanOld
     * @param stockHistoryBean
     */
    private void sellIn(BigDecimal changeRate, BusinessHistoryBean businessHistoryBeanOld, StockHistoryBean stockHistoryBean, StockConfigureBean stockConfigureBean) {
        BusinessHistoryBean businessHistoryBean = getBusinessHistoryBean(stockHistoryBean, businessHistoryBeanOld, stockConfigureBean);
        if (businessHistoryBean.getBusinessNumber() > 0) {
            //成交方向  01:买入  02:卖出
            if (changeRate.intValue() > 1) {
                businessHistoryBean.setBusinessDirection("02");//卖出
                businessHistoryBean.setBusinessNumber(businessHistoryBeanOld.getBusinessNumber());//成交数量
                businessHistoryBean.setBusinessAmount(stockHistoryBean.getClosePrice().multiply(new BigDecimal(businessHistoryBeanOld.getBusinessNumber())));//成交金额
                businessHistoryBean.setPreSalePrice(null);//预买价格
                //计算手续费 按照万三计算，最少5元
                BigDecimal sumFare = businessHistoryBean.getBusinessAmount().multiply(new BigDecimal(0.0003)).setScale(4, BigDecimal.ROUND_HALF_UP);
                businessHistoryBean.setSumFare(sumFare);
                if (sumFare.doubleValue() < 5)
                    businessHistoryBean.setSumFare(new BigDecimal(5));
            } else {
                businessHistoryBean.setBusinessDirection("01");//买入
            }

            if (StringUtils.equals(businessHistoryBean.getBusinessDirection(), "01")
                    && stockConfigureBean.getBusinessAmount().subtract(stockConfigureBean.getBuyAmount()).doubleValue() >= 0
                    && StringUtils.isBlank(businessHistoryBeanOld.getIsBuy())) {
                //新增
                businessHistoryWriterMapper.insert(businessHistoryBean);
                //更新买入标志
                businessHistoryWriterMapper.updateIsBuyById(businessHistoryBeanOld.getId());
                //更新配置信息
                updatetockonfigure(businessHistoryBean, null);
                //更新缓存
                updateRedis(businessHistoryBean);
                LOGGER.debug("买入股票【" + stockHistoryBean.getStockCode() + "  " + stockConfigureBean.getStockName() + "】数量：" + businessHistoryBean.getBusinessNumber() + " 成交单价：" + businessHistoryBean.getBusinessPrice() + " 成交金额：" + businessHistoryBean.getBusinessAmount());
            } else if (StringUtils.equals(businessHistoryBean.getBusinessDirection(), "02") && businessHistoryBeanOld.getOutId() == null) {
                //新增
                businessHistoryWriterMapper.insert(businessHistoryBean);
                //盈亏
                BigDecimal profitLoss = businessHistoryBean.getBusinessAmount().subtract(businessHistoryBeanOld.getBusinessAmount()).subtract(businessHistoryBean.getSumFare()).setScale(4, BigDecimal.ROUND_HALF_UP);
                //更新卖出ID 和盈亏
                businessHistoryWriterMapper.updateOutIdById(businessHistoryBeanOld.getId(), businessHistoryBean.getId(), profitLoss);
                //更新配置信息
                updatetockonfigure(businessHistoryBean, profitLoss);
                LOGGER.debug("卖出股票【" + stockHistoryBean.getStockCode() + "  " + stockConfigureBean.getStockName() + "】数量：" + businessHistoryBean.getBusinessNumber() + " 成交单价：" + businessHistoryBean.getBusinessPrice() + " 成交金额：" + businessHistoryBean.getBusinessAmount() + " 盈利：" + profitLoss +
                        "买入数量：" + businessHistoryBeanOld.getBusinessNumber() + "买入价格：" + businessHistoryBeanOld.getBusinessPrice() + " 买入金额：" + businessHistoryBeanOld.getBusinessAmount());
            }

        }
    }

    /**
     * 原卖出处理
     */
    private void sellOut(BigDecimal changeRate, BusinessHistoryBean businessHistoryBeanOld, StockHistoryBean stockHistoryBean, StockConfigureBean stockConfigureBean) {
        BusinessHistoryBean businessHistoryBean = getBusinessHistoryBean(stockHistoryBean, businessHistoryBeanOld, stockConfigureBean);
        //成交方向  01:买入  02:卖出
        businessHistoryBean.setBusinessDirection("01");//买入
        //新增
        businessHistoryWriterMapper.insert(businessHistoryBean);
        //更新买入标志
        businessHistoryWriterMapper.updateIsBuyById(businessHistoryBeanOld.getId());
        //更新业务数据
        businessHistoryWriterMapper.updateOutIdById(businessHistoryBeanOld.getId(), businessHistoryBean.getId(), null);
        //更新配置信息
        updatetockonfigure(businessHistoryBean, null);
        //更新缓存
        updateRedis(businessHistoryBean);
        LOGGER.debug("买入股票【" + stockHistoryBean.getStockCode() + "  " + stockConfigureBean.getStockName() + "】数量：" + businessHistoryBean.getBusinessNumber() + " 成交单价：" + businessHistoryBean.getBusinessPrice() + " 成交金额：" + businessHistoryBean.getBusinessAmount());
    }


    /**
     * 更新股票配置信息
     *
     * @param businessHistoryBean
     */
    private void updatetockonfigure(BusinessHistoryBean businessHistoryBean, BigDecimal profitLoss) {
        //获取股票配置信息
        StockConfigureBean stockConfigureBean = stockConfigureReaderMapper.selectByStockCode(businessHistoryBean.getStockCode());
        //现价
        BigDecimal presentPrice = StockUtils.getStockPrice(stockConfigureBean.getStockCode());
        if (StringUtils.equals(businessHistoryBean.getBusinessDirection(), "01")) {//买入
            /**数量*/
            stockConfigureBean.setBusinessNumber(businessHistoryBean.getBusinessNumber() + stockConfigureBean.getBusinessNumber());
            /**现金*/
            stockConfigureBean.setProfitLossAmount(stockConfigureBean.getProfitLossAmount().subtract(businessHistoryBean.getBusinessAmount()));
        } else {//卖出
            /**数量*/
            stockConfigureBean.setBusinessNumber(stockConfigureBean.getBusinessNumber() - businessHistoryBean.getBusinessNumber());
            /**总收益*/
            stockConfigureBean.setSumProfilt(profitLoss.add(stockConfigureBean.getSumProfilt()));
            /**现金*/
            stockConfigureBean.setProfitLossAmount(stockConfigureBean.getProfitLossAmount().add(businessHistoryBean.getBusinessAmount()));
        }
        /**市值*/
        stockConfigureBean.setBusinessAmount(presentPrice.multiply(new BigDecimal(stockConfigureBean.getBusinessNumber())));
        //更新股票配置信息
        stockConfigureWriterMapper.updateByPrimaryKeySelective(stockConfigureBean);
    }

    /**
     * 更新市值
     *
     * @param stockConfigureBean
     */
    private void updateBusinessAmount(StockConfigureBean stockConfigureBean) {
        if (stockConfigureBean != null && stockConfigureBean.getBusinessNumber().doubleValue() > 0) {
            //现价
            BigDecimal presentPrice = StockUtils.getStockPrice(stockConfigureBean.getStockCode());
            /**市值*/
            stockConfigureBean.setBusinessAmount(presentPrice.multiply(new BigDecimal(stockConfigureBean.getBusinessNumber())));
            //更新股票配置信息
            stockConfigureWriterMapper.updateBusinessAmount(stockConfigureBean.getId(), stockConfigureBean.getStockCode(), stockConfigureBean.getBusinessAmount());
        }
    }

    /**
     * 更新缓存
     *
     * @param businessHistoryBean
     */
    private void updateRedis(BusinessHistoryBean businessHistoryBean) {
        if (StringUtils.equals(businessHistoryBean.getBusinessDirection(), "01")) {//买入
            //根据股票代码获取买入总金额
            BigDecimal totalMarketValue = businessHistoryReaderMapper.getTotalMarketValue(businessHistoryBean.getStockCode());
            //获取缓存总金额
            Object maxTatalAmount = redisTemplate.opsForValue().get(businessHistoryBean.getStockCode() + "BusinessHistoryMaxTotalAmount");
            if (maxTatalAmount == null)
                maxTatalAmount = "0";

            if (totalMarketValue.subtract(new BigDecimal(maxTatalAmount + "")).doubleValue() > 0) {
                redisTemplate.opsForValue().set(businessHistoryBean.getStockCode() + "BusinessHistoryMaxTotalAmount", totalMarketValue);
            }
        }
    }


}
